/*
 * MIT License
 *
 * Copyright (c) 2020 wen.gu <454727014@qq.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/***************************************************************************
 * Name: uds_listener.cpp
 *
 * Purpose: implementation a listener as server side to listen the connection from client side
 *
 * Developer:
 *   wen.gu , 2025-01-05
 *
 * TODO:
 *
 ***************************************************************************/

#include "udssipc/uds/uds_listener.h"

#include "crt/osal/socket_uds.h"


#define CRT_LOG_TAG "UdsL"
#include "crt/log/log.h"


#define LISTENER_ACCPET_INTERVAL_MS (40)

namespace udssipc::uds {

Listener::Listener(const std::string& url) 
    :url_(url) {
    //todo something
}

Listener::~Listener() {
    stop();
}


core::UdssErrC Listener::start(OnConnectHandler handler) {
    if (!handler) {
        return core::UdssErrC::InvalidArgument;
    }

    std::unique_lock<std::mutex> al(lock_);
    if (url_.empty() || accept_worker_) {
        return core::UdssErrC::InvalidStatus;
    }

    crt_socket_t sock_id = crt_socket_uds_open();
    if (sock_id == CRT_SOCKET_INVALID_SOCK) {
        CRT_LOGE("open uds socket for (%s) failed: %s\n", url_.c_str(), crt_socket_last_error_str());
        return core::UdssErrC::SocketOpenFailed;
    }

    int32_t ret = crt_socket_uds_bind(sock_id, url_.c_str(), 0, 10, true);

    if (ret != 0) {
        CRT_LOGE("bind uds socket for (%s) failed: %s\n", url_.c_str(), crt_socket_last_error_str());
        crt_socket_close(sock_id);
        return core::UdssErrC::BindFailed;        
    }

    is_running_ = true;
    server_sock_ = sock_id;

    accept_worker_ = new std::thread([this, handler](){
        while (this->is_running_) {
            core::UdsSocketId client_sock = UDS_INVALID_SOCKET_ID;
            int32_t ret = crt_socket_uds_accept(this->server_sock_, &client_sock, LISTENER_ACCPET_INTERVAL_MS);
            if (ret == 0) {
                handler(client_sock);
            }
        }
    });

    return core::UdssErrC::OK;
}

core::UdssErrC Listener::stop() {
    std::unique_lock<std::mutex> al(lock_);
    if (accept_worker_) {
        is_running_ = false;
        accept_worker_->join();
        delete accept_worker_;
        accept_worker_ = nullptr;
    }
    return core::UdssErrC::OK;
}

} //namespace udssipc::uds